import { I_srv, Tsrv, ifs, ts, tvs } from '@/services';
import Vue from 'vue';

// Q1: 消息的前端存储方式？A：消息记录在表中，前端在store中记录消息的总数（消息分类的数）。
// Q2: 消息UI？——待后续完成

// todo：监听消息变化，更新消息信息（方式：监听store中各类消息的总数） Message statistics / message category count

export class T_msgHandler {
  private srv: I_srv;

  constructor(srv: I_srv) {
    this.srv = srv;
  }

  // 1、发送消息 （注意：消息的代理{转发、抄送...}）
  /**
   * @description: 发送消息 （注意：消息的代理{转发、抄送...}）
   * @description: 备注：消息命令为MESSAGE = 0的消息
   * @param {string} userNo // 接收消息的用户编号
   * @param {I_msgContent} msgContent // 消息内容 { mode：number, title: string, data: object}
   * @param {V_msgType} msgType 0 广播、1 预警、2 警报、3 通知、4 待办事项、 5 更新token
   * @param {V_msgCommand} msgCommand 0 普通消息、1 数据采集类、2 会谈
   * @param {string} clientID // 接收消息的客户端ID
   * @return {*}
   * @author: swc
   * @Date: 2024-09-25 09:51:00
   * @LastEditors: zss
   * @LastEditTime: Do not edit
   */
  public sendMsg(
    userNo: string,
    msgContent: ifs.I_msgContent,
    msgType: tvs.V_msgType = 0,
    msgCommand: tvs.V_msgCommand = 0,
    clientID: string = null
  ) {
    return new Promise((resolve, reject) => {
      const msg = new ts.T_wsMsg();
      msg
        .setMsgType(msgType)
        .setCMD(msgCommand)
        .setData(msgContent);
      // msgCommand === 0时存在消息代理，大于0直接发送消息
      // if (msgCommand > 0) {
      if (msgCommand === 0) {
        msg.setToUserNo(userNo).setToClientID(clientID);
        this.srv.sendMsg(msg).then(r => {
          resolve(r);
        });
      }
      // 检查消息是否代理
      const gpd = new ts.T_getPartDataArg();
      gpd.setFunName('getMsgProxy').setLang(this.srv.store.state.App.language);
      gpd.setPage(1, 99999).setDbType(this.srv.globalVar.dbType.MYSQL);
      gpd.setFilter({ xxx: { $in: [userNo] } });
      this.srv
        .getData<any, ifs.I_getPartDataArg>(gpd)
        .then(([b, res, rows, m]) => {
          if (!b) {
            m && Vue.prototype.$Message.info(m);
          }
          if (rows.length > 0) {
            // 存在代理 rows[0]
            msg.setToUserNo(userNo).setToClientID(clientID);
          } else {
            msg.setToUserNo(userNo).setToClientID(clientID);
          }
          // 发送消息
          this.srv.sendMsg(msg).then(r => {
            resolve(r);
          });
        })
        .catch(er => {
          console.error('获取用户消息代理失败', er);
        });
    });
  }

  // 2、修改消息状态
  /**
   * @description: 修改消息状态
   * @description: 备注：消息命令为MESSAGE = 0的消息
   * @param {string} msgId // 消息ID
   * @param {number} type // 消息类型
   * @param {number} category // 消息类别
   * @return {*}
   * @author: swc
   * @Date: 2024-09-25 11:17:19
   * @LastEditors: zss
   * @LastEditTime: Do not edit
   */
  public modifyMsgRead(
    msgId: string,
    typeNo: tvs.V_msgType,
    category: string
  ): Promise<boolean> {
    return new Promise((resolve, reject) => {
      const tableName = this.srv.globalVar.tableName.SYS_MSG;
      const upd = new ts.T_ctdUpdRec();
      const filter = {
        id: { $in: [msgId] }
      };
      const updData = [new ts.T_fv().setField('f_status').setValue(1)]; // 已读
      upd.setData({}, filter, {} as ifs.I_rule, ...updData);
      this.srv
        .updRows(
          tableName,
          this.srv.globalVar.dbType.MYSQL,
          {} as ifs.I_rule,
          upd
        )
        .then(([ok, res, err]) => {
          if (!ok || !err) {
            res?.msg && Vue.prototype.$msg(err ?? res.msg);
            resolve(false);
          } else {
            // res?.msg && Vue.prototype.$msg(res.msg);
            const store = this.srv.store;
            const type = this.getMsgType(typeNo);
            // store.commit('DEL_SYSMSGCOUNT', [type, category, 'total']);
            // store.commit('DEL_SYSMSGCOUNT', [type, category, 'unread']);
            const delParams = {
              type: {
                key: type,
                value: typeNo
              },
              // category: {
              //   key: category,
              //   value: categoryNo
              // },
              category,
              status: 1
            };
            store.commit('DEL_SYSMSGTIPS', delParams);
            resolve(true);
          }
        })
        .catch(er => {
          reject(er);
        });
    });
  }

  // 删除、更新、新增消息传参

  // 3、删除消息
  /**
   * @description: 删除消息
   * @description: 备注：消息命令为MESSAGE = 0的消息
   * @param {string} msgId // 消息ID
   * @param {number} typeNo // 消息类型
   * @param {number} categoryNo // 消息类别
   * @return {*}
   * @author: swc
   * @Date: 2024-09-25 11:35:22
   * @LastEditors: zss
   * @LastEditTime: Do not edit
   */
  public deleteMsg(
    msgId: string,
    typeNo: tvs.V_msgType,
    category: string
  ): Promise<boolean> {
    return new Promise((resolve, reject) => {
      const tableName = this.srv.globalVar.tableName.SYS_MSG;
      const upd = new ts.T_ctdUpdRec();
      const filter = {
        id: { $in: [msgId] }
      };
      const updData = [
        new ts.T_fv().setField(Tsrv.globalVar.fieldName.msgStatus).setValue(2)
      ]; // 软删除
      upd.setData({}, filter, {} as ifs.I_rule, ...updData);
      this.srv
        .updRows(
          tableName,
          this.srv.globalVar.dbType.MYSQL,
          {} as ifs.I_rule,
          upd
        )
        .then(([ok, res, err]) => {
          if (!ok || !err) {
            res?.msg && Vue.prototype.$msg(err ?? res.msg);
            resolve(false);
          } else {
            const store = this.srv.store;
            const type = this.getMsgType(typeNo);
            // this.recordMsgHandleLog(); // 记录消息处理日志
            // store.commit('DEL_SYSMSGCOUNT', [type, category, 'total']);
            const delParams = {
              type: {
                key: type,
                value: typeNo
              },
              // category: {
              //   key: category,
              //   value: categoryNo
              // }
              category
            };
            store.commit('DEL_SYSMSGTIPS', delParams);
            resolve(true);
          }
        })
        .catch(er => {
          reject(er);
        });
    });
  }

  // 4、查询消息（必须条件：用户。可选条件：消息状态、消息类型）
  /**
   * @description：查询消息
   * @description：备注：消息命令为MESSAGE = 0的消息
   * @param {V_msgType} msgType? 0 广播、1 预警、2 警报、3 通知、4 待办事项、 5 更新token
   * @param {number} status? 0 未读、1 已读
   * @return {*}
   * @author: swc
   * @Date: 2024-09-25 11:32:52
   * @LastEditors: zss
   * @LastEditTime: Do not edit
   */
  public queryMsg(msgType?: tvs.V_msgType | -1, status?: number): Promise<any> {
    return new Promise((resolve, reject) => {
      const tableName = this.srv.globalVar.tableName.SYS_MSG;
      const gpd = new ts.T_getPartDataArg();
      const filters: Array<any> = [
        { user_no: { $in: [this.srv.store.state.User.userNo] } }
      ];
      if (!this.srv.noValue(msgType) && msgType !== -1) {
        filters.push({ data_type_i: { $in: [msgType] } });
      }
      const statusFilters = [0, 1];
      if (!this.srv.noValue(status)) {
        statusFilters.length = 0;
        statusFilters.push(status);
        filters.push({ f_status: { $in: statusFilters } });
      }
      gpd.setFunName(tableName).setLang(this.srv.store.state.App.language);
      gpd.setPage(1, 99999).setDbType(this.srv.globalVar.dbType.MYSQL);
      gpd.setFilter({ $and: filters });
      this.srv
        .getData<any, ifs.I_getPartDataArg>(gpd)
        .then(([b, res, rows, m]) => {
          if (!b) {
            m && Vue.prototype.$Message.info(m);
            resolve(false);
          } else {
            resolve(rows);
          }
        })
        .catch(er => {
          console.error('获取用户消息失败', er);
        });
    });
  }

  // 5、清除未读消息
  public clearUnreadMsg(): Promise<boolean | void> {
    const store = this.srv.store;
    const tableName = this.srv.globalVar.tableName.SYS_MSG;
    const dbType = this.srv.globalVar.dbType.MYSQL;
    const agreedFields = [this.srv.globalVar.fieldName.ID];
    const filter = new ts.T_filter();
    filter.filter = {
      user_no: { $in: [store.state.User.userNo] },
      f_status: 0
    };
    return this.srv
      .getDataWithOption(
        store.getters.Language,
        dbType,
        tableName,
        agreedFields,
        filter
      )
      .then(([b, res, rows, msg]) => {
        if (b && rows.length > 0) {
          const ctd = new ts.T_ctdArg();
          ctd
            .setTableName(tableName)
            .setDbType(dbType)
            .setRule({} as ifs.I_rule);
          let ctdFilter: any = {};
          const ctdUpdDatas: ifs.I_ctdUpdData[] = [];
          rows.forEach(ele => {
            const ctdUpdData = new ts.T_ctdUpdData();
            ctdUpdData.setDataRule({} as ifs.I_rule).setFileInfo({});
            const rowData: ifs.I_fv[] = [];
            ctdFilter = { id: ele.id };
            rowData.push(
              new ts.T_fv()
                .setField(this.srv.globalVar.fieldName.msgStatus)
                .setValue(1)
            );
            ctdUpdData.setFilter(ctdFilter);
            ctdUpdData.setRowData(...rowData);
            ctdUpdDatas.push(ctdUpdData);
          });
          ctd.setUpdRecDataMany(...ctdUpdDatas);
          Tsrv.batRows(ctd).then(resp => {
            const [cb, cres, cmsg] = resp;
            cmsg && Vue.prototype.$msg(cmsg ?? cres.msg);
            if (cb) {
              // 修改状态成功后，更新store中的消息数量
              this.srv.store.commit('CLEAR_SYSMSGTIPS');
            }
          });
        } else {
          msg && Vue.prototype.$msg(msg ?? res.msg);
        }
      });
  }

  // better
  // 1、记录消息操作日志  （什么人、时间——已读、发送消息、删除消息、在PC端还是移动端）
  /**
   * @description: 记录消息操作日志  （什么人、时间——已读、发送消息、删除消息、在PC端还是移动端）
   * @description: 备注：消息命令为MESSAGE = 0的消息
   * @param {string} msgId // 消息ID
   * @return {*}
   * @author: swc
   * @Date: 2024-09-25 13:57:55
   * @LastEditors: zss
   * @LastEditTime: Do not edit
   */
  private async recordMsgHandleLog(): Promise<boolean | string> {
    const tableName = 'SYS_MSG_LOG';
    const data: Array<ifs.I_fv> = [
      new ts.T_fv()
        .setField(this.srv.globalVar.fieldName.ID)
        .setValue(await this.srv.getSnowIDFmtStr())
      // 后续补充
    ];
    const ins = new ts.T_ctdInsRec();
    ins.setScope({}).setBaseDataGeneral({} as ifs.I_rule, {}, ...data);
    const [ok, res, err] = await this.srv.addRows(
      tableName,
      this.srv.globalVar.dbType.MYSQL,
      {} as ifs.I_rule,
      ins
    );
    if (!ok || !err) {
      Vue.prototype.$msg(err ?? res.msg);
      return '新建内部联络单失败';
    }
    return true;
  }

  // 整理消息类别统计
  /**
   * @description: 修改store中的消息数量
   * @description: 备：后续需要修改： 类型/类别编号使用map规范
   * @param {tvs} typeNo 消息类型编号
   * @param {number} categoryNo 消息类别编号
   * @param {boolean} isAdd 是否增加
   * @param {'total' | 'unread'} msgStatus 删除消息时有效即：isAdd === false时（意为：删除的是已读还是未读消息）
   * @return {*}
   * @author: swc
   * @Date: 2024-09-25 17:51:17
   * @LastEditors: zss
   * @LastEditTime: Do not edit
   */
  public handleMsgStoreCount(
    typeNo: tvs.V_msgType,
    category: string,
    // msgStatus: tvs.V_msgStatus = tvs.V_msgStatus.UNREAD
    status: 0 | 1
  ) {
    const type = this.getMsgType(typeNo);
    // 更新 store 消息数量
    if (!this.srv.noValues(type, category)) {
      const store = this.srv.store;
      const addParams = {
        type: {
          key: type,
          value: typeNo
        },
        // category: {
        //   key: category,
        //   value: categoryNo
        // },
        category,
        status
      };
      store.commit('ADD_SYSMSGTIPS', addParams);
    }
  }

  public msgAddStoreCount(
    typeNo: tvs.V_msgType,
    category: string,
    status: 0 | 1
  ) {
    const type = this.getMsgType(typeNo);
    // 更新 store 消息数量
    if (!this.srv.noValues(type, category, status)) {
      const store = this.srv.store;
      if (status === 0) {
        store.commit('ADD_SYSMSGCOUNT', [type, category, 'unread']);
      }
      store.commit('ADD_SYSMSGCOUNT', [type, category, 'total']);
    }
  }

  /**
   * @description: 修改store中的消息数量
   * @description: 备：后续需要修改： 类型/类别编号使用map规范
   * @param {tvs} typeNo 消息类型编号
   * @param {number} categoryNo 消息类别编号
   * @return {*}
   * @author: swc
   * @Date: 2024-09-25 17:51:17
   * @LastEditors: zss
   * @LastEditTime: Do not edit
   */
  public getMsgType(typeNo: tvs.V_msgType) {
    let type: string = '';
    switch (typeNo) {
      case tvs.V_msgType.BROADCAST:
        type = 'broadcast';
        break;
      case tvs.V_msgType.EARLY_WARNING:
        type = 'earlyWarning';
        break;
      case tvs.V_msgType.ALARM:
        type = 'alarm';
        break;
      case tvs.V_msgType.NOTICE:
        type = 'notify';
        break;
      case tvs.V_msgType.TO_DO_LIST:
        type = 'todo';
        break;
      default:
        throw new Error(Tsrv.getI18nByValue('无此消息类型'));
    }
    return type;
  }
}
export interface I_msgHandler extends T_msgHandler {}
